package com.zhang.common.core.utils;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @Class com.zhang.common.core.utils
 * @Author zhang
 * @Date 2025/9/11 10:39
 * @Description 时间工具类
 **/
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {

    /**
     * 日志打印
     */
    public static final Logger logger = LoggerFactory.getLogger(DateUtils.class);

    /**
     * 年度
     */
    public static String YYYY = "yyyy";

    /**
     * 年月
     */
    public static String YYYY_MM = "yyyy-MM";

    /**
     * 年月日
     */
    public static String YYYY_MM_DD = "yyyy-MM-dd";

    /**
     * 年月日 时分秒
     */
    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    /**
     * 年月日 时分秒 数据集
     */
    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 获取当前 Date 型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return new Date();
    }

    /**
     * 获取指定格式的当前日期
     *
     * @param format 指定格式
     * @return 返回指定格式的当前日期
     */
    public static String getNowDate(String format) {
        return dateTimeNow(format);
    }

    /**
     * 将当前日期转为指定格式字符串形式
     *
     * @param format 指定格式
     * @return 返回指定格式日期
     */
    public static String dateTimeNow(final String format) {
        return parseDateToStr(format, new Date());
    }

    /**
     * 获取指定格式的指定日期字符串
     *
     * @param format 指定格式
     * @param date 指定日期
     * @return 返回指定格式指定日期的字符串
     */
    public static String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 指定格式 字符串日期
     * 将指定字符串日期格式转为日期格式
     *
     * @param format 指定格式
     * @param ts 字符串日期
     * @return 返回指定字符串格式日期
     */
    public static Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            logger.error("指定字符串日期格式转为日期格式异常: {}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 当前日期路径 - 年/月/日
     *
     * @return 返回当前日期路径字符串
     */
    public static String datePath() {
        return DateFormatUtils.format(new Date(), "yyyy/MM/dd");
    }

    /**
     * 指定格式当前日期的路径字符串 - 年/月/日
     *
     * @param format 指定格式
     * @return 返回指定格式当前日期的路径字符串
     */
    public static String datePath(String format) {
        return DateFormatUtils.format(new Date(), format);
    }

    /**
     * 指定日期的路径字符串 - 年/月/日
     *
     * @param date 指定日期
     * @return 返回指定日期的路径字符串
     */
    public static String datePath(Date date) {
        return DateFormatUtils.format(date, "yyyy/MM/dd");
    }

    /**
     * 指定格式指定日期的路径字符串 - 年/月/日
     *
     * @param date 指定日期
     * @param format 指定格式
     * @return 返回指定格式指定日期的路径字符串
     */
    public static String datePath(Date date, String format) {
        return DateFormatUtils.format(date, format);
    }

    /**
     * 日期型字符串转化为日期指定格式
     *
     * @param str 指定日期格式
     * @return 返回指定格式日期的日期
     */
    public static Date parseDate(Object str) {
        // 对象判空
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            logger.error("日期型字符串转化为日期指定格式异常: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     *
     * @param endDate 结束日期
     * @param nowDate 开始日期
     * @return 返回两个时间的时间差
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 将指定 LocalDateTime 转为 Date
     *
     * @param temporalAccessor LocalDateTime类型的日期 - 包含时分秒
     * @return 返回转换后的日期
     */
    public static Date toDate(LocalDateTime temporalAccessor) {
        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 将指定 LocalDateTime 转为 Date
     *
     * @param temporalAccessor LocalDateTime类型的日期 - 不包含时分秒
     * @return 返回转换后的日期
     */
    public static Date toDate(LocalDate temporalAccessor) {
        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
        return toDate(localDateTime);
    }

    /**
     * 获取指定日期几天之前|后的日期
     *
     * @param date 指定格式的日期字符串
     * @param format 指定日期格式
     * @param day  加减的天数
     * @return 返回指定的日期
     */
    public static Date getDate(String date, String format, int day) {
        SimpleDateFormat formate = new SimpleDateFormat(format);
        Calendar cal = Calendar.getInstance();
        try {
            Date beforeOrAfterDate = formate.parse(date);
            cal.setTime(beforeOrAfterDate);
            cal.add(Calendar.DAY_OF_MONTH, day);
            return cal.getTime();
        } catch (ParseException e) {
            logger.error("获取指定日期几天之前|后的日期异常: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 获取某个日期 在加上 秒数的时间
     *
     * @param beforeDate yyyy-MM-dd HH:mm:ss
     * @param timeSecond 加减的秒数
     */
    public static String getDateStr(Date beforeDate, Long timeSecond) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            // 返回毫秒数 + 添加的毫秒数
            Long time = beforeDate.getTime() + timeSecond * 1000;
            return format.format(time);
        } catch (Exception e) {
            logger.error("某个日期加上指定秒数时间异常: {}", e.getMessage());
        }
        return "";
    }


    /**
     * 获取指定格式某个时间段内所有日期
     *
     * @param begin 指定格式的开始日期
     * @param end 指定格式的结束日期
     * @param format 指定日期格式
     * @return 返回该时间段内的所有日期
     */
    public static List<String> getDayBetweenDates(String begin, String end, String format) {
        Date dBegin = strToDateTime(begin);
        Date dEnd = strToDateTime(end);
        List<String> lDate = new ArrayList<>();
        SimpleDateFormat sd = new SimpleDateFormat(format);
        lDate.add(sd.format(dBegin));
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            lDate.add(sd.format(calBegin.getTime()));
        }
        return lDate;
    }

    /**
     * 将指定日期格式字符串转为日期格式
     *
     * @param dateTime 指定日期格式日期字符串
     * @return 返回转换后的日期
     */
    public static Date strToDateTime(String dateTime) {
        Date date = null;
        try {
            // 指定包含时分秒的日期
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            date = format.parse(dateTime);
        } catch (ParseException e) {
            logger.error("指定日期格式字符串转为日期格式异常: {}", e.getMessage());
        }
        return date;
    }

}
